package il.ac.technion.wiki.api;

import il.ac.technion.wiki.api.IWikiEngine.IWikiContent;
import il.ac.technion.wiki.api.search.ISearchExpression;

/**
 * Defines an interface for a data store engine used by the wiki
 * engine to store its data. This provides an abstracted interface
 * for accessing the underlying data storage method, whatever it
 * may be.
 */
public interface IDataStore {
	/**
	 * Represents a general error accessing the data-store.
	 *
	 */
	public static class DataStoreException extends Exception {
		private static final long serialVersionUID = -6232966054912755637L;
	}
	
	/**
	 * Indicates that an operation failed because a specified name already exists
	 * in the data-store.
	 *
	 */
	public static class NameExistsException extends DataStoreException {
		private static final long serialVersionUID = 5523728906556153173L;
	}
	
	/**
	 * Indicates that an operation failed because a specified name could not
	 * be found in the data-store.
	 *
	 */
	public static class NotFoundException extends DataStoreException {
		private static final long serialVersionUID = 7665304677645222289L;
	}
	
	/**
	 * Specifies a concrete type of wiki content objects to use. This is necessary because
	 * the data-store must instantiate appropriate WikiContent objects, but must not be
	 * tied to any specific class of wiki-content, or of the wiki itself.
	 * This <b>must</b> be specified before any other operations are performed on the data-
	 * store. The results otherwise are undefined.
	 * The wiki engine should take care of setting this up when it is initialized.
	 * @param clazz	The class of wiki-content to use.
	 */
	public void setContentClass(Class<? extends IWikiContent> clazz);
	
	/**
	 * Specifies a concrete wiki engine object to use. This is necessary because
	 * the data-store must instantiate appropriate WikiContent objects, which are always
	 * tied to a specific wiki engine.
	 * This <b>must</b> be specified before any other operations are performed on the data-
	 * store. The results otherwise are undefined.
	 * The wiki engine should take care of setting this up when it is initialized.
	 * @param wikiEngine	The wiki engine object to use.
	 */
	public void setWikiEngine(IWikiEngine wikiEngine);
	
	/**
	 * Specifies a list of neutral words. (Words to ignore when performing a search.)
	 * @param words	A string array of neutral words.
	 */
	public void setNeutralWords(String words[]);
	
	/**
	 * Retrieve a piece of wiki content with a specified name.
	 * @param name		The name of the content to retrieve.
	 * @param revision	The revision number for the version to retrieve. Set this to 0
	 * 					to retrieve the latest version.
	 * @return		The retrieved content.
	 * @throws NotFoundException	If the given name was not found.
	 * @throws DataStoreException	If access to the data-store fails or the specified revision
	 * 								number is invalid.
	 */
	public IWikiContent get(String name, int revision) throws NotFoundException, DataStoreException;
	
	/**
	 * Save a piece of wiki content to the data-store.
	 * This allows both adding new content to the data-store, as well as modifying existing
	 * content - based on the value passed with the insert argument.
	 * If an update operation is specified and the content's revision number is lower than
	 * that of the content in the database, this will cause the specified revision to overwrite
	 * the historical version, dropping all history older than the specified revision number.
	 * This can be used as a rollback mechanism, but keep in mind that in addition to rolling back
	 * the revision history, the information for the specified revision is also overwritten with that
	 * of the passed-in content; this could cause you to accidentally change history if you're not
	 * careful...
	 * @param content	The piece of wiki content to save.
	 * @param insert	When <tt>true</tt>, will attempt to insert the content as a new piece of content
	 * 					into the data-store; this may fail if another piece of content with the
	 * 					same name already exists. When <tt>false</tt>, will attempt to modify an existing
	 * 					piece of content; this too may fail if content with the given name does
	 * 					not exist in the data-store.
	 * @throws NotFoundException	If the given name was not found when performing an update
	 * 								operation (with <tt>insert</tt>=<tt>false</tt>).
	 * @throws NameExistsException	If the given name already exists, when performing an insert
	 * 								operation (with <tt>insert</tt>=<tt>true</tt>).
	 * @throws DataStoreException	If access to the data-store fails.
	 */
	public void put(IWikiContent content, Boolean insert) throws	NotFoundException,
																	NameExistsException,
																	DataStoreException;
	
	/**
	 * Delete a piece of content from the data-store. This operation cannot be undone!
	 * @param name	The name of the content to delete.
	 * @throws NotFoundException	If the given name was not found.
	 * @throws DataStoreException	If access to the data-store fails.		
	 */
	public void delete(String name) throws NotFoundException, DataStoreException;
	
	/**
	 * Renames a piece of content.
	 * This operation preserves the versioning history, in addition to likely being more
	 * efficient than invoking {@link #put} for the new name, followed by {@link #delete}
	 * for the old one.
	 * @param name		The name of the content to rename.
	 * @param new_name	The new name to assign to the content.s
	 * @throws NotFoundException	If no content with the name exists.
	 * @throws NameExistsException	If the new name is already in use.
	 * @throws DataStoreException	If access to the data-store fails.	
	 */
	public void rename(String name, String new_name) throws	NotFoundException,
															NameExistsException,
															DataStoreException;
	
	/**
	 * Searches the data-store for entries whose content matches the specified search-expression.
	 * Even if you somehow have available the names of content entries in the data-store, it is
	 * preferable to use this method in place of using {@link #get} to retrieve them one by
	 * one, as this method may be able to more efficiently search the underlying storage.
	 * @param expr	The search expression to match.
	 * @param limit	An optional limit on the number of search results to be returned. Set this
	 * 				to 0 or a negative value in order to return all results.
	 * @return		An array of IWikiContent objects that matched the search expression.
	 * @throws DataStoreException	If the operation fails for any reason.
	 */
	public IWikiContent[] search(ISearchExpression expr, int limit) throws DataStoreException;
}
